package cc.owoo.godpen.network.http;

import cc.owoo.godpen.util.N;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Locale;

/**
 * 抽象的地址信息
 * Created by nimensei
 * 2022-02-27 上午 01:58
 **/
public class AbstractHost extends AbstractContent {
    public static final HashSet<String> DOMAIN_NAME = new HashSet<>();// 所有国际、国家域名

    static {
        Collections.addAll(DOMAIN_NAME, "com", "edu", "gov", "int", "mil", "net", "org", "biz", "info", "pro", "name", "museum", "coop", "aero", "xxx", "idv", "al", "dz", "af", "ar", "ae", "aw", "om", "az", "eg", "et", "ie", "ee", "ad", "ao", "ai", "ag", "at", "au", "mo", "bb", "pg", "bs", "pk", "py", "ps", "bh", "pa", "br", "by", "bm", "bg", "mp", "bj", "be", "is", "pr", "ba", "pl", "bo", "bz", "bw", "bt", "bf", "bi", "bv", "kp", "gq", "dk", "de", "tl", "tp", "tg", "dm", "do", "ru", "ec", "er", "fr", "fo", "pf", "gf", "tf", "va", "ph", "fj", "fi", "cv", "fk", "gm", "cg", "cd", "co", "cr", "gg", "gd", "gl", "ge", "cu", "gp", "gu", "gy", "kz", "ht", "kr", "nl", "an", "hm", "hn", "ki", "dj", "kg", "gn", "gw", "ca", "gh", "ga", "kh", "cz", "zw", "cm", "qa", "ky", "km", "ci", "kw", "cc", "hr", "ke", "ck", "lv", "ls", "la", "lb", "lt", "lr", "ly", "li", "re", "lu", "rw", "ro", "mg", "im", "mv", "mt", "mw", "my", "ml", "mk", "mh", "mq", "yt", "mu", "mr", "us", "um", "as", "vi", "mn", "ms", "bd", "pe", "fm", "mm", "md", "ma", "mc", "mz", "mx", "nr", "np", "ni", "ne", "ng", "nu", "no", "nf", "na", "za", "aq", "gs", "eu", "pw", "pn", "pt", "jp", "se", "ch", "sv", "ws", "yu", "sl", "sn", "cy", "sc", "sa", "cx", "st", "sh", "kn", "lc", "sm", "pm", "vc", "lk", "sk", "si", "sj", "sz", "sd", "sr", "sb", "so", "tj", "tw", "th", "tz", "to", "tc", "tt", "tn", "tv", "tr", "tm", "tk", "wf", "vu", "gt", "ve", "bn", "ug", "ua", "uy", "uz", "es", "eh", "gr", "hk", "sg", "nc", "nz", "hu", "sy", "jm", "am", "ac", "ye", "iq", "ir", "il", "it", "in", "id", "uk", "vg", "io", "jo", "vn", "zm", "je", "td", "gi", "cl", "cf", "cn", "ac", "ad", "ae", "af", "ag", "ai", "al", "am", "an", "ao", "aq", "ar", "as", "at", "au", "aw", "az", "ba", "bb", "bd", "be", "bf", "bg", "bh", "bi", "bj", "bm", "bn", "bo", "br", "bs", "bt", "bv", "bw", "by", "bz", "ca", "cc", "cd", "cf", "cg", "ch", "ci", "ck", "cl", "cm", "cn", "co", "cr", "cu", "cv", "cx", "cy", "cz", "de", "dj", "dk", "dm", "do", "dz", "ec", "ee", "eg", "eh", "er", "es", "et", "eu", "fi", "fj", "fk", "fm", "fo", "fr", "ga", "gd", "ge", "gf", "gg", "gh", "gi", "gl", "gm", "gn", "gp", "gq", "gr", "gs", "gt", "gu", "gw", "gy", "hk", "hm", "hn", "hr", "ht", "hu", "id", "ie", "il", "im", "in", "io", "iq", "ir", "is", "it", "je", "jm", "jo", "jp", "ke", "kg", "kh", "ki", "km", "kn", "kp", "kr", "kw", "ky", "kz", "la", "lb", "lc", "li", "lk", "lr", "ls", "lt", "lu", "lv", "ly", "ma", "mc", "md", "mg", "mh", "mk", "ml", "mm", "mn", "mo", "mp", "mq", "mr", "ms", "mt", "mu", "mv", "mw", "mx", "my", "mz", "na", "nc", "ne", "nf", "ng", "ni", "nl", "no", "np", "nr", "nu", "nz", "om", "pa", "pe", "pf", "pg", "ph", "pk", "pl", "pm", "pn", "pr", "ps", "pt", "pw", "py", "qa", "re", "ro", "ru", "rw", "sa", "sb", "sc", "sd", "se", "sg", "sh", "si", "sj", "sk", "sl", "sm", "sn", "so", "sr", "st", "sv", "sy", "sz", "tc", "td", "tf", "tg", "th", "tj", "tk", "tl", "tm", "tn", "to", "tp", "tr", "tt", "tv", "tw", "tz", "ua", "ug", "uk", "um", "us", "uy", "uz", "va", "vc", "ve", "vg", "vi", "vn", "vu", "wf", "ws", "ye", "yt", "yu", "yr", "za", "zm", "zw");
    }

    String agreement;// 协议版本
    InetAddress host;// 请求的主机地址
    int port = -1;// 请求的主机端口

    @Override
    public void initialize() {
        super.initialize();
        agreement = null;
        host = null;
        port = -1;
    }

    /**
     * 拷贝对象
     *
     * @param abstractRequest 拷贝源
     */
    public void copySetHost(AbstractHost abstractRequest) {
        agreement = abstractRequest.agreement;
        host = abstractRequest.host;
        port = abstractRequest.port;
    }

    /**
     * 解析地址
     *
     * @param url 地址
     * @return 解析之后，剩下的路径和参数部分
     */
    String analysisHost(String url) {
        if (url == null)
            return null;
        int index = url.indexOf("://");
        if (index != -1) {
            setAgreement(url.substring(0, index).trim());
            url = url.substring(index + "://".length());
        } else
            setAgreement(agreement);
        String host;
        String path;
        index = url.indexOf('/');
        if (index == -1) {
            host = url;
            path = "";
        } else {
            host = url.substring(0, index);
            path = url.substring(index);
        }
        return analysisHostPort(host) ? path : url;
    }

    /**
     * 解析主机地址和的口号
     *
     * @param host 字符串
     */
    private boolean analysisHostPort(String host) {
        int index = host.indexOf(':');
        if (index != -1) {
            setPort(Integer.parseInt(host.substring(index + 1)));
            host = host.substring(0, index);
        } else {
            int before = host.lastIndexOf('.');
            if (before == -1)
                return false;
            String name = host.substring(before + 1).toLowerCase(Locale.ROOT);
            if (!DOMAIN_NAME.contains(name) && !N.isNumber(name))
                return false;
            setPort(-1);
        }
        setHostString(host);
        return true;
    }

    /**
     * 获取请求使用的协议，一般为http或https
     *
     * @return 请求使用的协议
     */
    public String getAgreement() {
        return agreement;
    }

    /**
     * 设置求使用的协议，一般为http或https
     *
     * @param agreement 请求使用的协议
     */
    void setAgreement(String agreement) {
        this.agreement = agreement == null ? null : agreement.toLowerCase();
    }

    /**
     * 设置准备请求的主机值，该值可能是域名或是IP
     *
     * @param host 准备请求的主机值
     */
    boolean setHostString(String host) {
        if (host == null || (host = host.trim()).length() == 0) {
            this.host = null;
            return false;
        }
        try {
            this.host = InetAddress.getByName(host);
            return true;
        } catch (UnknownHostException e) {
            this.host = null;
            return false;
        }
    }

    /**
     * 设置请求的主机地址
     *
     * @param host 请求的主机地址
     */
    void setHost(InetAddress host) {
        this.host = host;
    }

    /**
     * 获取请求的端口号，一般为80、443、8080等
     *
     * @return 请求的端口号
     */
    public int getPort() {
        return port < 0 ? agreement != null && agreement.equals("https") ? 443 : 80 : port;
    }

    /**
     * 设置请求的端口号，一般为80、443、8080等
     *
     * @param port 请求的的口号
     */
    void setPort(int port) {
        if (port < 0)
            port = -1;
        this.port = port;
    }

    /**
     * 获取请求的主机地址
     *
     * @return 请求的主机地址
     */
    public InetAddress getHost() {
        return host;
    }

    /**
     * 获取远程主机的IP地址与端口号
     *
     * @return IP地址与端口号
     */
    public String getAddressPort() {
        return getAddressPort(":");
    }

    /**
     * 获取远程主机的IP地址与端口号
     *
     * @param interval 分隔符
     * @return IP地址与端口号
     */
    public String getAddressPort(String interval) {
        if (host == null)
            return null;
        return host.getHostAddress() + interval + getPort();
    }
}
